#pragma once
#include <string>
#include <vector>
#include <regex>

namespace Extension
{

    std::string replace(std::string_view source, std::string_view findStr, std::string_view replacement)
    {
        using namespace std;
        // Make a copy of the haystack.
        string result{source};

        // Find all needles and replace them with the replacement string.
        auto position{result.find(findStr)};
        while (position != string::npos)
        {
            result.replace(position, findStr.length(), replacement);
            position = result.find(findStr, position + findStr.size() - 1);
        }

        return result;
    }

    // 函数指针声明， 用于处理字符串split时，可以对分离出的字符进行处理。
    typedef bool (*SpiltTextProcess)(std::string &);

    class StringUtil
    {
    public:
        inline static std::string &trim(std::string &str);
        inline static std::string &trimPrefix(std::string &str, const char *prefix = " ");
        inline static std::string &trimEnd(std::string &str, const char *suffix = " ");
        inline static bool contains(std::string const &str1, std::string const &str2);
        inline static std::vector<std::string> split(std::string const &source, const std::string &characters, SpiltTextProcess predict = nullptr);
    };

    inline std::string &StringUtil::trim(std::string &str)
    {
        if (!str.empty())
        {
            str.erase(str.find_last_not_of(" \t\r\n") + 1);
            str.erase(0, str.find_first_not_of(" \t\r\n"));
        }
        return str;
    }

    inline std::string &StringUtil::trimPrefix(std::string &str, const char *prefix)
    {
        if (!str.empty())
            str.erase(0, str.find_first_not_of(prefix));

        return str;
    }

    inline std::string &StringUtil::trimEnd(std::string &str, const char *suffix)
    {
        if (!str.empty())
            str.erase(str.find_last_not_of(suffix) + 1);
        return str;
    }

    inline bool StringUtil::contains(std::string const &str1, std::string const &str2)
    {
        return !(str1.find(str2) == std::string::npos);
    }

    inline std::vector<std::string> StringUtil::split(std::string const &source, const std::string &characters, SpiltTextProcess predict)
    {
        std::vector<std::string> result;
        std::regex reg(characters);
        const std::sregex_token_iterator end;
        for (std::sregex_token_iterator iter{std::cbegin(source), std::cend(source), reg, -1}; iter != end; ++iter)
        {
            //  auto first = iter->first;
            //  auto second = iter->second;
            auto str = iter->str();

            if (predict)
            {
                if (predict(str))
                    result.push_back(std::move(str));
            }
            else
            {
                result.push_back(std::move(str));
            }
        }
        return result;
    }

} // namespace Extension
